home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 10 - 1994 / 10.09 Sep 94 / Fez (MacHack Winner) / FezEdit ƒ / Main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-20  |  32.6 KB  |  1,345 lines  |  [TEXT/MMCC]

  1. /*
  2.     FezEdit: Frame-Evading Zoomrects Editor
  3.     
  4.      by Douglas McKenna
  5.          (c) Copyright 1994 All rights reserved.
  6.  
  7.          Mathemaesthetics, Inc.
  8.         PO Box 298 • Boulder • CO • 80306-0298 • USA
  9.         
  10.         Submitted as a hack and a half for MacHack, June 24, 1994
  11.         Winner (by popular acclaim) of Best Hack of the Contest
  12.         
  13.          Permission is granted to use this code in any non-commercial product.
  14.          Please contact the author for prior written approval for use in any
  15.          commercial or shareware product.
  16.          
  17.     This file contains the shell application for creating window's with a
  18.     double-clickable and dragable widget icon in them that opens into another
  19.     window.  This provides a testbed for the FEZ routines, described in the
  20.     accompanying file, "FEZ.c".
  21.  */
  22.  
  23.  
  24. #include "Main.h"
  25. #include "Utilities.h"
  26. #include "FEZ.h"
  27.  
  28. #define kDefaultPosition    NIL
  29.  
  30. /* Global variables for whole app */
  31.  
  32. SysEnvRec            thisMac;
  33.  
  34. /* Global variables for this file's routines only */
  35.  
  36. static EventRecord    myEvent;
  37. static int            appleEventsOK,quitting,firstTime=TRUE;
  38. static MenuHandle    appleMenu,fileMenu,demoMenu,optionsMenu,editMenu;
  39. static MenuHandle    windowMenu,openWindowMenu,closeWindowMenu;
  40. static CIconHandle    fezHat,fezHatSelected;
  41.  
  42. static WindowPtr    windows[MAXWINDOWS];
  43. static Rect            windowPosition[MAXWINDOWS];
  44. static Rect            windowWidgetPosition[MAXWINDOWS];
  45. static short        zoomStyle,lineThick,speed,theDemo,qSize;
  46. static Rect            stdWidgetPosition = { 50, 50, 50+WIDGETHEIGHT, 50+WIDGETWIDTH };
  47.  
  48. static AEEventHandlerUPP odocUPP;
  49. static AEEventHandlerUPP oappUPP;
  50. static AEEventHandlerUPP pdocUPP;
  51. static AEEventHandlerUPP quitUPP;
  52.  
  53.  
  54. /* Prototypes for local routines */
  55.  
  56. void            main(void);
  57. void            Initialize(void);
  58.  
  59. void            InstallCoreEventHandlers(void);
  60. void            DoHighLevelEvent(EventRecord *evt);
  61. pascal OSErr    HandleOAPP(AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  62. pascal OSErr     HandleODOC(AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  63. pascal OSErr     HandlePDOC(AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  64. pascal OSErr     HandleQUIT(AppleEvent *appleEvent, AppleEvent *reply, long refcon);
  65. int                DoOpenApplication(void);
  66. OSErr            MyGotRequiredParams(AppleEvent *appleEvent);
  67.  
  68. int                MainEvent(void);
  69. int                DoMouseDown(short modifiers);
  70. void            DoContentClick(WindowPtr aWindow, Point p);
  71. void            SelectWidget(WidgetHandle item, int selected);
  72. int                DoMouseUp(void);
  73. void            DoActivate(WindowPtr w, int activ);
  74. void            DoUpdate(WindowPtr w);
  75. void            UpdateAllWindows(void);
  76. Rect *            SetInteriorClipping(WindowPtr w);
  77. void            RestoreInteriorClipping(WindowPtr w);
  78. int                DoKeyDown(void);
  79. void            DoGrow(WindowPtr w);
  80. int                DoMenu(long choice, short modifiers);
  81. void            RebuildDemoMenu(void);
  82. void            InstallDemo(short i);
  83. void            RecordCurrentDemo(short modifiers);
  84.  
  85. int                IsDoubleClick(Point *pt, long *time, int tol);
  86. Rect            *StaggeredWindowBounds(short index);
  87. short            NextFreeWindowIndex(void);
  88. WindowPtr        NewWidgetWindow(void);
  89. WindowPtr        CreateWidgetWindow(short index, Rect *bounds, Rect *widgetSpot, int show);
  90. void            DoAppleMenu(int choice);
  91. void            DispatchEvent(EventRecord *evt);
  92. void            FixMenus(void);
  93. WidgetHandle    CloseZoom(WindowPtr w);
  94. WidgetHandle    CloseWidgetWindow(WindowPtr w);
  95. short            RecordPositions(WindowPtr w);
  96. WindowPtr        OpenWidgetWindow(WindowPtr w);
  97. void            DrawWidget(WidgetHandle item);
  98. void            CloseAllWindows(int reset);
  99.  
  100. void main()
  101.     {
  102.         Initialize();
  103.         
  104.         while (MainEvent())    ;            /* Life until event-ual death */
  105.     }
  106.  
  107.  
  108. void Initialize()
  109.     {
  110.  
  111.         /* Usual Mac Toolbox startup calls */
  112.         
  113.         MaxApplZone();
  114.         InitGraf(&qd.thePort);
  115.         InitFonts();
  116.         InitWindows();
  117.         InitCursor();
  118.         InitMenus();
  119.         InitDialogs(0L);
  120.         FlushEvents(everyEvent, 0 );
  121.         
  122.         /* Figure out what's legal on this machine */
  123.         
  124.         SysEnvirons(1,&thisMac);
  125.         appleEventsOK = (thisMac.systemVersion >= 0x0700);    /* Should be using Gestalt */
  126.         
  127.         /* Install Apple Event stuff */
  128.         
  129.         if (appleEventsOK)
  130.             InstallCoreEventHandlers();
  131.         
  132.         /* Install menus */
  133.         
  134.         appleMenu = GetMenu(appleMenuID);
  135.         AddResMenu(appleMenu,'DRVR');
  136.         InsertMenu(appleMenu,0);
  137.         fileMenu = GetMenu(fileMenuID);
  138.         InsertMenu(fileMenu,0);
  139.         openWindowMenu = GetMenu(openWindowMenuID);
  140.         InsertMenu(openWindowMenu,-1);
  141.         closeWindowMenu = GetMenu(closeWindowMenuID);
  142.         InsertMenu(closeWindowMenu,-1);
  143.         
  144.         editMenu = GetMenu(editMenuID);
  145.         InsertMenu(editMenu,0);
  146.         optionsMenu = GetMenu(optionsMenuID);
  147.         InsertMenu(optionsMenu,0);
  148.         demoMenu = GetMenu(demoMenuID);
  149.         InsertMenu(demoMenu,0);
  150.         windowMenu = GetMenu(windowMenuID);
  151.         InsertMenu(windowMenu,0);
  152.         
  153.         zoomStyle = OM_NoZooms;
  154.         CheckItem(optionsMenu,zoomStyle,TRUE);
  155.         theDemo = DM_None;
  156.         CheckItem(demoMenu,theDemo,TRUE);
  157.         lineThick = 1;
  158.         speed = 1;
  159.         qSize = 4;
  160.         
  161.         RebuildDemoMenu();
  162.         
  163.         DrawMenuBar();
  164.         
  165.         /* Do pre-allocations */
  166.                 
  167.         fezHat = GetCIcon(fezHatColorIconID);
  168.         if (fezHat == NIL) ExitToShell();
  169.         fezHatSelected = GetCIcon(fezHatSelectedID);
  170.         if (fezHatSelected == NIL) ExitToShell();
  171.     }
  172.  
  173. /*
  174.  *    Install the addresses of the functions that the AppleEvent manager will
  175.  *    call when any of the standard core events come in over the transom.
  176.  */
  177.  
  178. static void InstallCoreEventHandlers()
  179.     {
  180.         OSErr err;
  181.         
  182.         oappUPP = NewAEEventHandlerProc(HandleOAPP);
  183.         odocUPP = NewAEEventHandlerProc(HandleODOC);
  184.         pdocUPP = NewAEEventHandlerProc(HandlePDOC);
  185.         quitUPP = NewAEEventHandlerProc(HandleQUIT);
  186.         
  187.         err = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,oappUPP,0,FALSE);
  188.         if (err) goto broken;
  189.         err = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,odocUPP,0,FALSE);
  190.         if (err) goto broken;
  191.         err = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,pdocUPP,0,FALSE);
  192.         if (err) goto broken;
  193.         err = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,quitUPP,0,FALSE);
  194. broken:
  195.         if (err) {
  196.             }
  197.     }
  198.  
  199. pascal OSErr HandleOAPP(AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  200.     {
  201.         OSErr err = noErr, keepGoing = TRUE;
  202.         
  203.         err = MyGotRequiredParams(appleEvent);
  204.         if (!err)
  205.             keepGoing = DoOpenApplication();
  206.         
  207.         return(err);
  208.     }
  209.  
  210. /*
  211.  *    Check to see that all required parameters have been retrieved (IM 6-47)
  212.  */
  213.  
  214. static OSErr MyGotRequiredParams(AppleEvent *appleEvent)
  215.     {
  216.         DescType returnedType;
  217.         Size actualSize;
  218.         OSErr err;
  219.         
  220.         err = AEGetAttributePtr(appleEvent,keyMissedKeywordAttr,typeWildCard,
  221.                                                             &returnedType,NIL,0,&actualSize);
  222.         if (err == errAEDescNotFound) return(noErr);
  223.         if (!err) err = errAEEventNotHandled;
  224.         
  225.         return(err);
  226.     }
  227.     
  228. static int DoOpenApplication()
  229.     {
  230.         int keepGoing = TRUE;
  231.                 
  232.         return(keepGoing);
  233.     }
  234.  
  235. pascal OSErr HandleODOC(AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  236.     {
  237.         OSErr err = noErr;
  238.         long iFile,nFiles,numErrs=0;
  239.         Size actualSize;
  240.         AEKeyword keywd;
  241.         DescType returnedType;
  242.         AEDescList docList;
  243.         FSSpec theFile;
  244.         
  245.         err = AEGetParamDesc(appleEvent, keyDirectObject, typeAEList, &docList);
  246.  
  247.         err = MyGotRequiredParams(appleEvent);
  248.         if (!err) {
  249.             AECountItems(&docList,&nFiles);
  250.             for (iFile=1; iFile<=nFiles; iFile++) {
  251.                 err = AEGetNthPtr(&docList,iFile,typeFSS,&keywd,&returnedType,
  252.                                                 (Ptr)&theFile,sizeof(FSSpec),&actualSize);
  253.                 if (err) {
  254.                     break;
  255.                     }
  256.                  else {
  257.                     }
  258.                 }
  259.             }
  260.  
  261.         AEDisposeDesc(&docList);
  262.         
  263.         return(err);
  264.     }
  265.  
  266. pascal OSErr HandlePDOC(AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  267.     {
  268.         short err;
  269.         
  270.         err = HandleODOC(appleEvent,reply,refcon);
  271.         return(err);
  272.     }
  273.  
  274. pascal OSErr HandleQUIT(AppleEvent *appleEvent, AppleEvent *reply, long refcon)
  275.     {
  276.         int keepGoing = DoMenu(FM_Quit,0);
  277.         quitting = !keepGoing;
  278.         
  279.         return(keepGoing);
  280.     }
  281.  
  282.  
  283. /*
  284.  *    Process next event, return TRUE if okay to continue
  285.  */
  286.  
  287. int MainEvent()
  288.     {
  289.         int gotOne;
  290.         static int lastWasNull = FALSE;
  291.         
  292.         gotOne = WaitNextEvent(everyEvent,&myEvent,0,NIL);
  293.         
  294.         if (gotOne) {
  295.             FixMenus();
  296.             DispatchEvent(&myEvent);
  297.             lastWasNull = FALSE;
  298.             }
  299.          else {
  300.             /* Null event */
  301.             SetCursor(&qd.arrow);
  302.             if (!lastWasNull) FixMenus();
  303.             lastWasNull = TRUE;
  304.             }
  305.                     
  306.         return(!quitting);
  307.     }
  308.  
  309. /*
  310.  *    Figure out what kind of event we've gotten, and deal with it
  311.  */
  312.  
  313. void DispatchEvent(EventRecord *evt)
  314.     {
  315.         WindowPtr w; short result;
  316.        
  317.            quitting = FALSE;
  318.            
  319.         switch (evt->what) {
  320.             case mouseDown:
  321.                 quitting = DoMouseDown(evt->modifiers);
  322.                 break;
  323.             case mouseUp:
  324.                 quitting = DoMouseUp();
  325.                 break;
  326.             case keyDown:
  327.             case autoKey:
  328.                 quitting = DoKeyDown();
  329.                 break;
  330.             case activateEvt:
  331.                 w = (WindowPtr)evt->message;
  332.                 DoActivate(w,(myEvent.modifiers & activeFlag)!=0);
  333.                 break;
  334.             case updateEvt:
  335.                 w = (WindowPtr)evt->message;
  336.                 DoUpdate(w);
  337.                 break;
  338.                 
  339.             case diskEvt:
  340.                 result = HiWord(myEvent.message);
  341.                 if (result) {
  342.                     Point corner;
  343.                     /* ??? Can dialog box be centered    */
  344.                     /*   There doesn't appear to be a    */
  345.                     /*   DLOG resource for this one.    */
  346.                     /*   Location (112,80) is the value    */
  347.                     /*   used by Finder 6.1.             */
  348.                     SetPt(&corner, 112, 80);
  349.                     result = DIBadMount(corner, myEvent.message);
  350.                     }
  351.                 break;
  352.                 
  353.             case app4Evt:
  354.                 switch(myEvent.message >> 24) {
  355.                     case mouseMovedMessage:
  356.                         break;
  357.                     case suspendResumeMessage:
  358.                         w = FrontWindow();
  359.                         if (w) 
  360.                             DoActivate(w,(myEvent.message & 1) != 0);
  361.                         break;
  362.                     }
  363.                 break;
  364.                 
  365.             case kHighLevelEvent:
  366.                 DoHighLevelEvent(&myEvent);
  367.                 break;
  368.             
  369.             default:
  370.                 break;
  371.             }
  372.     }
  373.  
  374. static void DoHighLevelEvent(EventRecord *evt)
  375.     {
  376.         OSErr err = noErr;
  377.         
  378.         /* No high level events supported yet except for the core events */
  379.         
  380.         if (evt->message == (long)kCoreEventClass) {
  381.             err = AEProcessAppleEvent(evt);
  382.             }
  383.     }
  384.  
  385. /*
  386.  *    Call this for an activate/deactivate event
  387.  */
  388.  
  389. void DoActivate(WindowPtr w, int activ)
  390.     {
  391.         SetPort(w);
  392.         DrawGrowIcon(w);
  393.     }
  394.  
  395. /*
  396.  *    Call this to redraw contents of given window.  In this testbed, all windows
  397.  *    are the same.
  398.  */
  399.  
  400. void DoUpdate(WindowPtr w)
  401.     {
  402.         WidgetHandle item;
  403.         
  404.         PushPort(w);
  405.         BeginUpdate(w);
  406.         
  407.         DrawGrowIcon(w);
  408.         
  409.         SetInteriorClipping(w);
  410.         
  411.         item = (WidgetHandle)GetWRefCon(w);
  412.         DrawWidget(item);
  413.         
  414.         RestoreInteriorClipping(w);
  415.         
  416.         EndUpdate(w);
  417.         PopPort();
  418.     }
  419.  
  420. /*
  421.  *    Clip the window to its content region within scroll bar bounds.  Delivers a pointer
  422.  *    to the clipping rectangle.
  423.  */
  424.  
  425. Rect *SetInteriorClipping(WindowPtr w)
  426.     {
  427.         static Rect clipper;
  428.         
  429.         clipper = w->portRect;
  430.         clipper.right -= SCROLLBARWIDTH-1;
  431.         clipper.bottom -= SCROLLBARWIDTH-1;
  432.         ClipRect(&clipper);
  433.         
  434.         return(&clipper);
  435.     }
  436.  
  437. /*
  438.  *    Restore the current window's clipping region to whatever it was when
  439.  *    when PushContent was called.
  440.  */
  441.  
  442. void RestoreInteriorClipping(WindowPtr w)
  443.     {
  444.         ClipRect(&w->portRect);
  445.     }
  446.  
  447. /*
  448.  *    Draw the window's widget at its current position.  The handle to the window widget
  449.  *    is always in the refCon field, and it's always defined.
  450.  */
  451.         
  452. void DrawWidget(WidgetHandle item)
  453.     {
  454.         Rect position;
  455.         
  456.         position = (*item)->position;                // Local coordinates
  457.         PlotCIcon(&position,(*item)->isSelected ? fezHatSelected : fezHat);
  458.     }
  459.  
  460. /*
  461.  *    Call this for a mouse up event
  462.  */
  463.  
  464. int DoMouseUp()
  465.     {
  466.         return(FALSE);
  467.     }
  468.  
  469. /*
  470.  *    Call this for a mouse down click anywhere
  471.  */
  472.  
  473. int DoMouseDown(short modifiers)
  474.     {
  475.         short part; Point p; int done = FALSE;
  476.         WindowPtr aWindow;
  477.         
  478.         p = myEvent.where;
  479.         part = FindWindow(p,&aWindow);
  480.         if (aWindow == NIL) {
  481.             switch(part) {
  482.                 case inDesk:
  483.                         break;
  484.                 case inMenuBar:
  485.                         done = DoMenu(MenuSelect(p),modifiers);
  486.                         break;
  487.                 }
  488.             }
  489.          else {
  490.             if (aWindow!=FrontWindow() && part!=inGrow) {
  491.                 SelectWindow(aWindow);
  492.                 }
  493.              else {
  494.                 switch(part) {
  495.                     case inContent:
  496.                             DoContentClick(aWindow,p);
  497.                             break;
  498.                     case inGoAway:
  499.                             if (TrackGoAway(aWindow,p)) {
  500.                                 if (modifiers & optionKey)
  501.                                     CloseAllWindows(FALSE);
  502.                                  else {
  503.                                     CloseWidgetWindow(aWindow);
  504.                                     }
  505.                                 }
  506.                             break;
  507.                     case inZoomIn:
  508.                     case inZoomOut:
  509.                             if (TrackBox(aWindow,p,part)) {
  510.                                 PushPort(aWindow);
  511.                                 EraseRect(&aWindow->portRect);
  512.                                 ZoomWindow(aWindow,part,TRUE);
  513.                                 DrawGrowIcon(aWindow);
  514.                                 InvalRect(SetInteriorClipping(aWindow));
  515.                                 RestoreInteriorClipping(aWindow);
  516.                                 PopPort();
  517.                                 }
  518.                             break;
  519.                     case inSysWindow:
  520.                             SystemClick(&myEvent,aWindow);
  521.                             break;
  522.                     case inDrag:
  523.                             DragWindow(aWindow,p,&qd.screenBits.bounds);
  524.                             break;
  525.                     case inGrow:
  526.                             DoGrow(aWindow);
  527.                             break;
  528.                     }
  529.                 }
  530.             }
  531.         return(done);
  532.     }    
  533.  
  534. /*
  535.  *    Deal with a mouse down click in the window's content region at the global
  536.  *    coordinate in given point.
  537.  */
  538.  
  539. void DoContentClick(WindowPtr aWindow, Point p)
  540.     {
  541.         short dx,dy; long now; Rect rect,*clip; OSErr err;
  542.         WidgetHandle item;
  543.         GWorldPtr offscreen,saveWorld; PixMapHandle pm;
  544.         GDHandle saveGDevice;
  545.         
  546.         // Get the widget in window, and its position
  547.         
  548.         item = (WidgetHandle)GetWRefCon(aWindow);
  549.         rect = (*item)->position;
  550.         GlobalToLocal(&p);
  551.         
  552.         // Don't overwrite scroll bar lines when dragging, selecting, or deselecting
  553.         clip = SetInteriorClipping(aWindow);
  554.         
  555.         // If click is on widget, select it and entertain a drag or double-click
  556.         // otherwise, deselect widget
  557.         
  558.         if (PtInRect(p,&rect)) {
  559.             now = TickCount();
  560.             if (IsDoubleClick(&p,&now,2)) {
  561.                 OpenWidgetWindow(aWindow);
  562.                 }
  563.              else {
  564.                 // First click always selects item if not already selected
  565.                 SelectWidget(item,TRUE);
  566.                 
  567.                 if (StillDown()) {
  568.                 
  569.                     // Prepare for a drag: use an offscreen graphics world to avoid flicker
  570.                     // If no offscreen world allocated, then we'll draw directly to screen
  571.                     // since both screen and offscreen will be using the same coordinates
  572.                     // Note that we could use temporary memory here, since we'll be throwing
  573.                     // it all away as soon as user lets up the mouse.
  574.                     
  575.                     GetGWorld(&saveWorld,&saveGDevice);
  576.                     err = NewGWorld(&offscreen,0,clip,NIL,NIL,noNewDevice);
  577.                     if (err == noErr) {
  578.                         SetGWorld(offscreen,NIL);
  579.                         pm = GetGWorldPixMap(offscreen);
  580.                         LockPixels(pm);
  581.                         EraseRect(clip);
  582.                         }
  583.                      else
  584.                         SysBeep(1);
  585.                     
  586.                     HideCursor();                    // So cursor doesn't flicker during drag
  587.                     
  588.                     while (WaitMouseUp()) {
  589.                         Point newPt;
  590.                         
  591.                         // Get new mouse position in window's local coordinates
  592.                         PushPort(aWindow);
  593.                         GetMouse(&newPt);
  594.                         PopPort();
  595.                         
  596.                         if (!EqualPt(p,newPt)) {
  597.                             // Mouse has moved to a new position: use offset to move widget
  598.                             dx = newPt.h - p.h;
  599.                             dy = newPt.v - p.v;
  600.                             EraseRect(&rect);            // Erase old icon bounds
  601.                             OffsetRect(&rect,dx,dy);    // Move icon to new position
  602.                             (*item)->position = rect;
  603.                             DrawWidget(item);            // Redraw it in current world
  604.                             // And update screen if above drawing was into offscreen world
  605.                             if (err == noErr)
  606.                                 CopyBits((BitMap *)*pm,&aWindow->portBits,clip,clip,srcCopy,NIL);
  607.                             // Move to new point and wait until another change in mouse position
  608.                             p = newPt;
  609.                             }
  610.                         }
  611.                     ShowCursor();
  612.                     // Drag done: clean up
  613.                     if (err == noErr) {
  614.                         UnlockPixels(pm);
  615.                         DisposeGWorld(offscreen);
  616.                         }
  617.                     SetGWorld(saveWorld,saveGDevice);
  618.                     }
  619.                 }
  620.             }
  621.          else {
  622.             SelectWidget(item,FALSE);                // Deselect it
  623.             }
  624.         
  625.         // Allow full content area to be drawn into again
  626.         RestoreInteriorClipping(aWindow);
  627.     }
  628.  
  629. /*
  630.  *    Given a widget in a window, set its selection state to 0 or 1 (selected)
  631.  *    and graphically draw the selection state now.
  632.  */
  633.  
  634. void SelectWidget(WidgetHandle item, int selected)
  635.     {
  636.         if ((selected!=0) ^ ((*item)->isSelected!=0)) {        // Only if this is an actual change
  637.             (*item)->isSelected = selected;
  638.             SetInteriorClipping((*item)->itsWindow);
  639.             DrawWidget(item);
  640.             RestoreInteriorClipping((*item)->itsWindow);
  641.             }
  642.     }
  643.  
  644. /*
  645.  *    Update our window and widget position table entries for the given window,
  646.  *    or for all windows if w is NIL.  Returns number of windows in table.
  647.  */
  648.  
  649. short RecordPositions(WindowPtr w)
  650.     {
  651.         short i,k=0; WidgetHandle item;
  652.         
  653.         // For each current window in our table...
  654.         for (i=0; i<MAXWINDOWS; i++)
  655.             if (windows[i]) {
  656.                 k++;
  657.                 // If we've matched given window, or we're doing all of them...
  658.                 if ((windows[i]==w || w==NIL)) {
  659.                 
  660.                     // Save widget position (local coords) for re-opening
  661.                     item = (WidgetHandle)GetWRefCon(windows[i]);
  662.                     windowWidgetPosition[i] = (*item)->position;
  663.         
  664.                     // Save global position of window on desktop for re-opening
  665.                     windowPosition[i] = windows[i]->portRect;
  666.                     LocalToGlobalRect(windows[i],&windowPosition[i]);
  667.                     }
  668.                 }
  669.         
  670.         return(k);
  671.     }
  672.  
  673. /*
  674.  *    Close the given window, disposing of its widget and zooming back to
  675.  *    the widget whence it came, if such widget is in some other window.
  676.  *    Delivers the widget that it zooms into, or NIL.
  677.  */
  678.  
  679. WidgetHandle CloseWidgetWindow(WindowPtr w)
  680.     {
  681.         short i; WidgetHandle closeItem = NIL;
  682.         
  683.         RecordPositions(w);
  684.         
  685.         if (w) {
  686.             // Find the entry in table, mark it free, and ditch the given window
  687.             for (i=0; i<MAXWINDOWS; i++) {
  688.                 if (windows[i] == w) {
  689.                     closeItem = CloseZoom(w);
  690.                     DisposeWindow(w);
  691.                     windows[i] = NIL;
  692.                     break;
  693.                     }
  694.                 }
  695.             }
  696.         
  697.         return(closeItem);
  698.     }
  699.  
  700. /*
  701.  *    Determine if the given window was opened from a widget in some other window,
  702.  *    and if so, zoom back to the widget position after hiding the window.
  703.  */
  704.  
  705. WidgetHandle CloseZoom(WindowPtr w)
  706.     {
  707.         Rect startBox = (*((WindowPeek)w)->strucRgn)->rgnBBox;
  708.         Rect endBox; WindowPeek wp;
  709.         WidgetHandle item,closeItem=NIL; ZoomFrame start,end; ZoomFrameHandle zoomArray;
  710.         
  711.         SetRect(&endBox,0,0,0,0);
  712.         wp = (WindowPeek)FrontWindow();
  713.         while (wp) {
  714.             closeItem = (WidgetHandle)GetWRefCon((WindowPtr)wp);
  715.             // If not desk accessory and item window is this window
  716.             if (wp->windowKind>=0 && closeItem!=NIL && (*closeItem)->openWindow==w) {
  717.                 // Detach item from its window, which is about to close
  718.                 (*closeItem)->openWindow = NIL;
  719.                 endBox = (*closeItem)->position;
  720.                 break;
  721.                 }
  722.             wp = wp->nextWindow;
  723.             }
  724.         
  725.         item = (WidgetHandle)GetWRefCon(w);
  726.         DisposeHandle((Handle)item);
  727.         
  728.         // Precalculate the multi-window zoom information before hiding window
  729.         
  730.         start.frame = startBox; start.win = w;
  731.         end.frame = endBox; end.win = (WindowPtr)wp;
  732.         start.thickness = end.thickness = lineThick;
  733.         zoomArray = NewZoom(&end,&start,FALSE,zoomStyle-OM_NoZooms);
  734.         
  735.         HideWindow(w);
  736.         
  737.         // Do the various flavors of zooming
  738.         
  739.         if (!EmptyRect(&endBox)) {
  740.             UpdateAllWindows();
  741.             //DoUpdate((WindowPtr)wp);        // Make widget visible if it's behind closed window
  742.             switch(zoomStyle) {
  743.                 case OM_NoZooms:
  744.                     break;
  745.                 case OM_StandardZooms:
  746.                     LocalToGlobalRect((WindowPtr)wp,&endBox);
  747.                     ZoomCenterRect(&startBox,&endBox,lineThick,speed,qSize);
  748.                     break;
  749.                 default:
  750.                     FrameEvadingZoom(zoomArray,speed,qSize);
  751.                     break;
  752.                 }
  753.             }
  754.         
  755.         DisposeZoom(zoomArray);
  756.         return(closeItem);
  757.     }
  758.  
  759. /*
  760.  *    Called for a key down event
  761.  */
  762.  
  763. int IsDoubleClick(Point *pt, long *time, int tol)
  764.     {
  765.         int ans = FALSE;
  766.         static long lastTime; static Point thePt;
  767.         
  768.         if (*time-lastTime < GetDblTime()) {
  769.             Rect box;
  770.             SetRect(&box,thePt.h-tol,thePt.v-tol,thePt.h+tol,thePt.v+tol);
  771.             ans = PtInRect(*pt,&box);
  772.             lastTime = 0;
  773.             thePt.h = thePt.v = -16000;
  774.             }
  775.          else {
  776.             lastTime = *time;
  777.             thePt = *pt;
  778.             }
  779.         return(ans);
  780.     }
  781.  
  782. int DoKeyDown()
  783.     {
  784.         int ch = (unsigned)(myEvent.message & charCodeMask);
  785.         
  786.         if (myEvent.modifiers & cmdKey) {
  787.             return( DoMenu(MenuKey(ch),myEvent.modifiers) );
  788.             }
  789.  
  790.         return(FALSE);
  791.     }
  792.  
  793. int DoMenu(long choice, short modifiers)
  794.     {
  795.         short menuID = HiWord(choice);
  796.         short menuCh = LoWord(choice);
  797.         short i,quitting = FALSE;
  798.         short newThick,newSpeed,newQueue;
  799.         WindowPtr w;
  800.         
  801.         switch(menuID) {
  802.             case appleMenuID:
  803.                 DoAppleMenu(menuCh);
  804.                 break;
  805.             case fileMenuID:
  806.                 switch(menuCh) {
  807.                     case FM_New:
  808.                         NewWidgetWindow();
  809.                         break;
  810.                     case FM_Open:
  811.                         /* Never happens: heirarchical */
  812.                         break;
  813.                     case FM_Close:
  814.                         /* Never happens: heirarchical */
  815.                         break;
  816.                     case FM_CloseAll:
  817.                         CloseAllWindows(FALSE);
  818.                         break;
  819.                     case FM_Quit:
  820.                         quitting = TRUE;
  821.                         break;
  822.                     }
  823.                 break;
  824.             case editMenuID:
  825.                 switch(menuCh) {
  826.                     case EM_SelectAll:
  827.                         w = FrontWindow();
  828.                         if (w) {
  829.                             WidgetHandle item = (WidgetHandle)GetWRefCon(w);
  830.                             SelectWidget(item,TRUE);
  831.                             }
  832.                         break;
  833.                     case EM_SendBehind:
  834.                         w = FrontWindow();
  835.                         if (w) SendBehind(w,NIL);
  836.                         break;
  837.                     }
  838.                 break;
  839.             case demoMenuID:
  840.                 switch(menuCh) {
  841.                     case DM_SaveDemo:
  842.                         RecordCurrentDemo(modifiers);
  843.                         break;
  844.                     case DM____2:
  845.                         break;
  846.                     case DM_None:
  847.                         CheckItem(demoMenu,theDemo,FALSE);
  848.                         CheckItem(demoMenu,theDemo = menuCh,TRUE);
  849.                         break;
  850.                     default:
  851.                         // Command is name of 'DEMO' resource with window config in it
  852.                         InstallDemo(menuCh);
  853.                         break;
  854.                     }
  855.                 break;
  856.             case optionsMenuID:
  857.                 switch(menuCh) {
  858.                     case OM_SetLine:
  859.                         newThick = GetLineThickOrSpeed(lineThick,0);
  860.                         if (newThick > 0) lineThick = newThick;
  861.                         break;
  862.                     case OM_SetSpeed:
  863.                         newSpeed = GetLineThickOrSpeed(speed,1);
  864.                         if (newSpeed >= 0) speed = newSpeed;
  865.                         break;
  866.                     case OM_SetQueue:
  867.                         newQueue = GetLineThickOrSpeed(qSize,2);
  868.                         if (newQueue > 0) qSize = newQueue;
  869.                         break;
  870.                     
  871.                     case OM_NoZooms:
  872.                     case OM_StandardZooms:
  873.                     case OM_OneWindowDive:
  874.                     case OM_FrameEvading:
  875.                         CheckItem(optionsMenu,zoomStyle,FALSE);
  876.                         CheckItem(optionsMenu,zoomStyle = menuCh,TRUE);
  877.                         firstTime = FALSE;
  878.                         break;
  879.                     }
  880.                 break;
  881.             case windowMenuID:
  882.             case openWindowMenuID:
  883.             case closeWindowMenuID:
  884.                 for (i=0; i<MAXWINDOWS; i++)
  885.                     if (windows[i] && --menuCh==0) {
  886.                         switch(menuID) {
  887.                             case windowMenuID:
  888.                                 SelectWindow(windows[i]);
  889.                                 break;
  890.                             case openWindowMenuID:
  891.                                 OpenWidgetWindow(windows[i]);
  892.                                 break;
  893.                             case closeWindowMenuID:
  894.                                 CloseWidgetWindow(windows[i]);
  895.                                 break;
  896.                             }
  897.                         break;
  898.                         }
  899.                 break;
  900.             }
  901.         
  902.         HiliteMenu(0);
  903.         return(quitting);
  904.     }
  905.  
  906. static void FixMenus()
  907.     {
  908.         WindowPtr w = FrontWindow();
  909.         short i,n,k;
  910.         
  911.         if (w) EnableItem(fileMenu,FM_Open);
  912.          else  DisableItem(fileMenu,FM_Open);
  913.         
  914.         if (w) EnableItem(fileMenu,FM_Close);
  915.          else  DisableItem(fileMenu,FM_Close);
  916.         
  917.         if (w) EnableItem(fileMenu,FM_CloseAll);
  918.          else  DisableItem(fileMenu,FM_CloseAll);
  919.  
  920.         for (i=EM_Undo; i<=EM_Paste; i++)
  921.             DisableItem(editMenu,i);
  922.         if (w) EnableItem(editMenu,EM_SelectAll);
  923.          else  DisableItem(editMenu,EM_SelectAll);
  924.         if (w) EnableItem(editMenu,0);
  925.          else  DisableItem(editMenu,0);
  926.         
  927.         if (theDemo == DM_None) DisableItem(demoMenu,DM_SaveDemo);
  928.          else                    EnableItem(demoMenu,DM_SaveDemo);
  929.         
  930.         // Rebuild the window menus
  931.         
  932.         n = CountMItems(windowMenu);
  933.         while (n > 0) {
  934.             DeleteMenuItem(windowMenu,n);
  935.             DeleteMenuItem(openWindowMenu,n);
  936.             DeleteMenuItem(closeWindowMenu,n);
  937.             n--;
  938.             }
  939.         
  940.         if (w) EnableItem(windowMenu,0);
  941.          else    DisableItem(windowMenu,0);
  942.         
  943.         k = 1;
  944.         for (i=0; i<MAXWINDOWS; i++)
  945.             if (windows[i]) {
  946.                 WindowPeek wp = (WindowPeek)windows[i];
  947.                 HLock((Handle)wp->titleHandle);
  948.                 AppendMenu(windowMenu,*wp->titleHandle);
  949.                 AppendMenu(openWindowMenu,*wp->titleHandle);
  950.                 AppendMenu(closeWindowMenu,*wp->titleHandle);
  951.                 if (windows[i] == FrontWindow()) {
  952.                     SetItemMark(windowMenu,k,'•');
  953.                     SetItemCmd(openWindowMenu,k,'O');
  954.                     SetItemCmd(closeWindowMenu,k,'W');
  955.                     }
  956.                 HUnlock((Handle)wp->titleHandle);
  957.                 k++;
  958.                 }
  959.         DrawMenuBar();
  960.     }
  961.  
  962. /*
  963.  *    Deal with a user choice from the Apple Menu: if not choosing "About Resorcerer..."
  964.  *    then it's a Desk Accessory to be opened.
  965.  */
  966.  
  967. static void DoAppleMenu(int choice)
  968.     {
  969.         Byte accName[256];
  970.         
  971.         switch(choice) {
  972.             case AM_About:
  973.                 if (thisMac.hasColorQD)
  974.                     Alert(aboutBoxAlertID,NIL);
  975.                  else
  976.                     Alert(BWaboutBoxAlertID,NIL);
  977.                 break;
  978.             default:
  979.                 GetItem(appleMenu,choice,accName);
  980.                 OpenDeskAcc(accName);
  981.                 break;
  982.             }
  983.     }
  984.  
  985. /*
  986.  *    Grow a window to a new size in response to click in grow box
  987.  */
  988.  
  989. void DoGrow(WindowPtr window)
  990.     {
  991.         Rect r;
  992.         long newSize; int x,y;
  993.         
  994.         r = qd.screenBits.bounds;
  995.         SetRect(&r,32,32,r.right-r.left,r.bottom-r.top);
  996.         newSize = GrowWindow(window,myEvent.where,&r);
  997.         if (newSize) {
  998.             x = LoWord(newSize); y = HiWord(newSize);
  999.             SizeWindow(window,x,y,TRUE);
  1000.             PushPort(window);
  1001.             EraseRect(&window->portRect);
  1002.             DrawGrowIcon(window);
  1003.             r = *SetInteriorClipping(window);
  1004.             InvalRect(&r);
  1005.             RestoreInteriorClipping(window);
  1006.             PopPort();
  1007.             }
  1008.     }
  1009.  
  1010. void RebuildDemoMenu()
  1011.     {
  1012.         short n;
  1013.         
  1014.         // Empty the menu, except for the first "No demo" entry, and the line after it
  1015.         for (n=CountMItems(demoMenu); n>DM_None; n--)
  1016.             DeleteMenuItem(demoMenu,n);
  1017.         
  1018.         // Append the names of all 'DEMO' resources to menu
  1019.         AddResMenu(demoMenu,'DEMO');
  1020.     }
  1021.  
  1022. /*
  1023.  *    Given a choice from the Demo menu (kDemo), retrieve the resource and use it
  1024.  *    to build a set of windows and widgets.
  1025.  */
  1026.  
  1027. void InstallDemo(short kDemo)
  1028.     {
  1029.         StartWindowHandle demo; StartWindow win; short i,k,numWins;
  1030.         WindowPtr w; Byte str[256]; int newOrdering,oldZoom,doClose;
  1031.         
  1032.         if (firstTime) {
  1033.             if (zoomStyle == OM_NoZooms) {
  1034.                 CheckItem(optionsMenu,zoomStyle,FALSE);
  1035.                 CheckItem(optionsMenu,zoomStyle=OM_FrameEvading,TRUE);
  1036.                 }
  1037.             firstTime = FALSE;
  1038.             }
  1039.  
  1040.         // Turn off any zooming while throwing away all current windows
  1041.         
  1042.         oldZoom = zoomStyle;
  1043.         zoomStyle = OM_NoZooms;
  1044.         CloseAllWindows(TRUE);                // Resets entire position table
  1045.         zoomStyle = oldZoom;
  1046.         
  1047.         Wait(20);
  1048.         
  1049.         GetItem(demoMenu,kDemo,str);
  1050.         demo = (StartWindowHandle)Get1NamedResource('DEMO',str);
  1051.         if (demo) {
  1052.         
  1053.             numWins = (*demo)->numWins;
  1054.             if (numWins > MAXWINDOWS) numWins = MAXWINDOWS;
  1055.             if (numWins == 0)
  1056.                 NewWidgetWindow();
  1057.              else {
  1058.                 newOrdering = doClose = FALSE;
  1059.                 for (i=0; i<numWins; i++) {
  1060.                     win = (*demo)->win[i];
  1061.                     
  1062.                     windowPosition[i] = win.position;
  1063.                     windowWidgetPosition[i] = win.fezBounds;
  1064.                     if (i == 0)
  1065.                         w = CreateWidgetWindow(i,&win.position,&win.fezBounds,TRUE);
  1066.                      else
  1067.                         w = OpenWidgetWindow(windows[i-1]);
  1068.                         
  1069.                     if (win.finalOrdering != (numWins-1-i))
  1070.                         newOrdering = TRUE;
  1071.                     if (win.closeOrdering != -1)
  1072.                         doClose = TRUE;
  1073.                     }
  1074.                 
  1075.                 /* Now rearrange open windows into final ordering if different */
  1076.                 if (newOrdering)
  1077.                     for (k=numWins-1; k>=0; k--)
  1078.                         for (i=0; i<numWins; i++) {
  1079.                              if ((*demo)->win[i].finalOrdering == k) {
  1080.                                  SelectWindow(windows[i]);
  1081.                                  DoUpdate(windows[i]);
  1082.                                  }
  1083.                              }
  1084.                 
  1085.                 // And close any windows in the order specified
  1086.                 if (doClose) {
  1087.                     WidgetHandle closeItem = NIL;
  1088.                     Wait(40);
  1089.                     for (k=numWins-1; k>=0 && closeItem==NIL; k--)
  1090.                         for (i=0; i<numWins; i++) {
  1091.                              if ((*demo)->win[i].closeOrdering == k) {
  1092.                                  closeItem = CloseWidgetWindow(windows[i]);
  1093.                                  break;
  1094.                                  }
  1095.                              }
  1096.                     if (closeItem) {
  1097.                         Wait(40);
  1098.                         OpenWidgetWindow((*closeItem)->itsWindow);
  1099.                         }
  1100.                     }
  1101.                 }
  1102.             
  1103.             CheckItem(demoMenu,theDemo,FALSE);
  1104.             CheckItem(demoMenu,theDemo = kDemo,TRUE);
  1105.             }
  1106.     }
  1107.  
  1108. /*
  1109.  *    Resize the demo resource for the current demo, and place into it the current
  1110.  *    positions and ordering of all the windows and their widgets.  If modifiers
  1111.  *    has option key on, record the front most window as to-be-closed.
  1112.  */
  1113.  
  1114. void RecordCurrentDemo(short modifiers)
  1115.     {
  1116.         StartWindowHandle demo; StartWindow *win;
  1117.         short i,k,numWins; WindowPtr w; Byte str[256];
  1118.  
  1119.         if (theDemo == DM_None) return;
  1120.         
  1121.         numWins = RecordPositions(NIL);
  1122.         
  1123.         GetItem(demoMenu,theDemo,str);
  1124.         demo = (StartWindowHandle)Get1NamedResource('DEMO',str);
  1125.         if (demo) {
  1126.         
  1127.             SetHandleSize((Handle)demo, sizeof(short) + numWins*sizeof(StartWindow));
  1128.             if (MemError()) return;
  1129.             
  1130.             /* Save the positions of windows and widgets into resource */
  1131.             
  1132.             HLock((Handle)demo);
  1133.             (*demo)->numWins = numWins;
  1134.             win = (*demo)->win;
  1135.             for (i=0; i<MAXWINDOWS; i++)
  1136.                 if (windows[i]) {
  1137.                     win->position = windowPosition[i];
  1138.                     win->fezBounds = windowWidgetPosition[i];
  1139.                     win->closeOrdering = (windows[i]==FrontWindow() && (modifiers&optionKey)!=0) ? (numWins-1) : -1;
  1140.                     for (k=0,w=FrontWindow(); w; w=(WindowPtr)((WindowPeek)w)->nextWindow,k++)
  1141.                         if (w == windows[i]) {
  1142.                             win->finalOrdering = k;
  1143.                             break;
  1144.                             }
  1145.                     win++;
  1146.                     }
  1147.             HUnlock((Handle)demo);
  1148.             
  1149.             ChangedResource((Handle)demo);
  1150.             UpdateResFile(CurResFile());
  1151.             }
  1152.     }
  1153.  
  1154. void CloseAllWindows(int reset)
  1155.     {
  1156.         WindowPtr w; short i;
  1157.         
  1158.         for (w=FrontWindow(); w; w=FrontWindow())
  1159.             CloseWidgetWindow(w);
  1160.         
  1161.         if (reset)
  1162.             for (i=0; i<MAXWINDOWS; i++) {
  1163.                 windows[i] = NIL;
  1164.                 SetRect(&windowPosition[i],0,0,0,0);
  1165.                 windowWidgetPosition[i] = stdWidgetPosition;
  1166.                 }
  1167.     }
  1168.  
  1169.  
  1170. /////////////////////////////////////////////////////////////////////////////////////////////////
  1171.  
  1172. /*
  1173.  *    Deliver the index of the first free window slot in table.  Delivers -1 if none.
  1174.  */
  1175.  
  1176. short NextFreeWindowIndex()
  1177.     {
  1178.         short index;
  1179.         
  1180.         for (index=0; index<MAXWINDOWS; index++)
  1181.             if (windows[index] == NIL)
  1182.                 return(index);
  1183.         return(-1);
  1184.     }
  1185.     
  1186. /*
  1187.  *    Create a new color window at the given position, and add a widget at the
  1188.  *    given position, or in the standard initial position if widgetSpot is NIL.
  1189.  *    The window title is built from the given index.
  1190.  *    Delivers the window's pointer, and does not show the window.
  1191.  */
  1192.  
  1193. WindowPtr CreateWidgetWindow(short index, Rect *bounds, Rect *widgetSpot, int show)
  1194.     {
  1195.         WindowPtr w=NIL; WidgetHandle item; Byte *title;
  1196.         
  1197.         if (index>=0 && index<MAXWINDOWS) {
  1198.         
  1199.             // Get a new widget first
  1200.             item = (WidgetHandle)NewHandleClear(sizeof(Widget));
  1201.             if (item) {
  1202.             
  1203.                 // Initialize widget
  1204.                 if (widgetSpot) (*item)->position = *widgetSpot;
  1205.                  else            (*item)->position = stdWidgetPosition;
  1206.                 (*item)->isSelected = FALSE;
  1207.                 
  1208.                 // Create the title using index
  1209.                 title = "\pFez xx";
  1210.                 if (index < 10)    { title[5] = '0'+index;                                title[0] = 5; }
  1211.                  else            { title[5] = '0'+index/10; title[6] = '0'+index%10; title[0] = 6; }
  1212.     
  1213.                 w = NewCWindow(NIL,bounds,title,FALSE,zoomDocProc,(WindowPtr)-1,TRUE,(long)item);
  1214.                 if (w) {
  1215.                     (*item)->itsWindow = w;
  1216.                     windows[index] = w;
  1217.                     windowPosition[index] = *bounds;
  1218.                     windowWidgetPosition[index] = (*item)->position;
  1219.                     if (show) { ShowWindow(w); DoUpdate(w); }
  1220.                     }
  1221.                  else
  1222.                     DisposeHandle((Handle)item);
  1223.                 }
  1224.             }
  1225.         
  1226.         return(w);
  1227.     }
  1228.  
  1229. /*
  1230.  *    Given an index, compute the bounds of its window using a formula
  1231.  *    that staggers the windows in groups of 8 on the main screen.
  1232.  */
  1233.  
  1234. Rect *StaggeredWindowBounds(short index)
  1235.     {
  1236.         static Rect ans; short x,y; Point pt;
  1237.         
  1238.         x = index / 8;
  1239.         y = index % 8;
  1240.         pt.h = 4;
  1241.         pt.v = 4 + GetMBarHeight();
  1242.         pt.h += 5 + 30*x + 5*y;
  1243.         pt.v += 20 + 20*y + 5*x;
  1244.         SetRect(&ans,100,100,300,300);
  1245.         OffsetRect(&ans,pt.h-ans.left,pt.v-ans.top);
  1246.         
  1247.         return(&ans);
  1248.     }
  1249.  
  1250. /*
  1251.  *    Create a new widget window that isn't attached to any previous widget and
  1252.  *    which gets placed at a standard position.
  1253.  */
  1254.  
  1255. WindowPtr NewWidgetWindow()
  1256.     {
  1257.         WindowPtr w=NIL; short index;
  1258.         
  1259.         index = NextFreeWindowIndex();
  1260.         if (index >= 0)
  1261.             w = CreateWidgetWindow(index,StaggeredWindowBounds(index),kDefaultPosition,TRUE);
  1262.          else
  1263.             SysBeep(1);
  1264.         
  1265.         return(w);
  1266.     }
  1267.  
  1268. /*
  1269.  *    Open another widget window on the desk top.  If parentWindow is non-NIL,
  1270.  *    then the window being opened belongs to the widget in parent window.
  1271.  *    Any zooming to be done gets done here.  Delivers the window's pointer.
  1272.  */
  1273.  
  1274. WindowPtr OpenWidgetWindow(WindowPtr parentWindow)
  1275.     {
  1276.         Rect bounds,rect,*initPos; short index;
  1277.         WindowPtr w=NIL; WidgetHandle item;
  1278.         ZoomFrame start,end; ZoomFrameHandle zoomArray;
  1279.         
  1280.         if (parentWindow) {
  1281.             // Check first for window whose widget is already in this window
  1282.             item = (WidgetHandle)GetWRefCon(parentWindow);
  1283.             if ((*item)->openWindow)
  1284.                 SelectWindow(w = (*item)->openWindow);
  1285.              else {
  1286.                 // Widget not yet opened: open first window slot for it
  1287.                 index = NextFreeWindowIndex();
  1288.                 if (index >= 0) {
  1289.                 
  1290.                     if (EmptyRect(&windowPosition[index])) {
  1291.                         bounds = *StaggeredWindowBounds(index);
  1292.                         initPos = kDefaultPosition;
  1293.                         }
  1294.                      else {
  1295.                         bounds = windowPosition[index];
  1296.                         initPos = &windowWidgetPosition[index];
  1297.                         }
  1298.                     w = CreateWidgetWindow(index,&bounds,initPos,FALSE);
  1299.                     if (w) {
  1300.                         // Attach window to its widget
  1301.                         (*item)->openWindow = w;
  1302.                         rect = (*item)->position;        // Of widget being opened, not new one
  1303.                         
  1304.                         // Precompute the zoom information and zoom before showing window
  1305.                         start.frame = rect; start.win = parentWindow; start.thickness = lineThick;
  1306.                         end.frame = bounds; end.win = w; end.thickness = lineThick;
  1307.                         zoomArray = NewZoom(&start,&end,TRUE,zoomStyle-OM_NoZooms);
  1308.                         
  1309.                         switch(zoomStyle) {
  1310.                             case OM_NoZooms:
  1311.                                 break;
  1312.                             case OM_StandardZooms:
  1313.                                 LocalToGlobalRect(parentWindow,&rect);
  1314.                                 ZoomCenterRect(&rect,&bounds,lineThick,speed,qSize);
  1315.                                 break;
  1316.                             default:
  1317.                                 FrameEvadingZoom(zoomArray,speed,qSize);
  1318.                                 break;
  1319.                             }
  1320.                         
  1321.                         ShowWindow(w);
  1322.                         DoUpdate(w);
  1323.                         DisposeZoom(zoomArray);
  1324.                         }
  1325.                     }
  1326.                  else
  1327.                     SysBeep(1);
  1328.                 }
  1329.             }
  1330.          else
  1331.             w = NewWidgetWindow();
  1332.         
  1333.         return(w);
  1334.     }
  1335.  
  1336. void UpdateAllWindows()
  1337.     {
  1338.         WindowPeek wp;
  1339.         
  1340.         for (wp=(WindowPeek)FrontWindow(); wp; wp=wp->nextWindow)
  1341.             if (wp->visible)
  1342.                 DoUpdate((WindowPtr)wp);        
  1343.     }
  1344.  
  1345.